#include "outtime_delay.h"
#include <math.h>       /* round, floor, ceil, trunc */
/*
    函数： int clock_gettime(clockid_t clk_id, struct timespec *tp);

clockid_t：                 用于指定计时时钟的类型，有以下几种类型：
CLOCK_REALTIME：            系统实时时间，从Epoch计时，可被设置更改。
CLOCK_MONOTONIC：           系统运行时间，从系统启动时开始计时，系统休眠时不再计时（NTP与硬件时钟有问题时会影响其频率，没有验证过）。
CLOCK_PROCESS_CPUTIME_ID：  本进程启动到此刻使用CPU的时间，当使用sleep等函数时不再计时。
CLOCK_THREAD_CPUTIME_ID：   本线程启动到此刻使用CPU的时间，当使用sleep等函数时不再计时。
CLOCK_MONOTONIC_RAW ：      系统运行时间，从系统启动时开始计时，系统休眠时不再计时（NTP与硬件时钟有问题时不会影响其频率，没有验证过）。
CLOCK_REALTIME_COARSE：     系统实时时间，从Epoch计时，可被设置更改，速度更快精度更低。
CLOCK_MONOTONIC_COARSE：    系统运行时间，从系统启动时开始计时，速度更快精度更低，系统休眠时不再计时（NTP与硬件时钟有问题时会影响其频率，没有验证过）。
CLOCK_BOOTTIME：            与CLOCK_MONOTONIC类似
CLOCK_REALTIME_ALARM ：     闹钟时间（应该休眠后继续计时，没验证过），系统实时时间，从Epoch计时，可被设置更改。
CLOCK_BOOTTIME_ALARM：      闹钟时间（应该休眠后继续计时，没验证过），系统运行时间，从系统启动时开始计时。
CLOCK_TAI：                 原子钟的时间，与CLOCK_REALTIME类似，不可被更改，没有闰秒。

    获取tick示例：
    struct timespec ttime;
    clock_gettime(CLOCK_MONOTONIC, &ttime);
*/

int get_clocktime(struct timespec *ttime)
{
    int ierro   = -1;
    ierro = clock_gettime(CLOCK_MONOTONIC,ttime);
    return ierro;
}

/**
	u32Timeout_ms : 设置超时的时间;  0-表示未设置超时功能。  
	ttime : 起始时间
	return : 0-超时 , 1-wake_ack , 2-未设置超时时间
	
*/
enum _outtime_delay_return_val_e  is_timeout(struct timespec ttime ,  uint64_t u64Timeout_ms)
{
    struct timespec tCurnTime;
    uint64_t u64ms = 0;
    if( 0 == u64Timeout_ms)
    {
        return OUTTIME_DELAY_RETURN_VAL_NO_SET_OUTTIME;
    }
    clock_gettime(CLOCK_MONOTONIC,&tCurnTime);
    if(tCurnTime.tv_sec < ttime.tv_sec)
    {
        return OUTTIME_DELAY_RETURN_VAL_ERR;
    }
    tCurnTime.tv_sec    -= ttime.tv_sec;
    if(tCurnTime.tv_nsec < ttime.tv_nsec)
    {
        tCurnTime.tv_nsec += (1000000000 - ttime.tv_nsec);
    }
    else
    {
        tCurnTime.tv_nsec -= ttime.tv_nsec;
    }
    u64ms = (int)round(tCurnTime.tv_nsec / 1000000);
    u64ms += tCurnTime.tv_sec * 1000;

    if(u64ms >=  u64Timeout_ms)
        return OUTTIME_DELAY_RETURN_VAL_OUTTIME;

    return OUTTIME_DELAY_RETURN_VAL_WAIT_OUTTIME;
    
}

/*
    is_timeout函数的拓展；
    如未超时，增加返回剩余时间ms；
*/
enum _outtime_delay_return_val_e remaining_timeout_val(struct timespec ttime ,  uint64_t u64Timeout_ms, uint64_t* pu64out_remaining_time_val)
{
    struct timespec tCurnTime;
    uint64_t u64ms = 0;
    if( 0 == u64Timeout_ms)
    {
        return OUTTIME_DELAY_RETURN_VAL_NO_SET_OUTTIME;
    }
    clock_gettime(CLOCK_MONOTONIC,&tCurnTime);
    if(tCurnTime.tv_sec < ttime.tv_sec)
    {
        return OUTTIME_DELAY_RETURN_VAL_ERR;
    }
    tCurnTime.tv_sec    -= ttime.tv_sec;
    if(tCurnTime.tv_nsec < ttime.tv_nsec)
    {
        tCurnTime.tv_nsec += (1000000000 - ttime.tv_nsec);
    }
    else
    {
        tCurnTime.tv_nsec -= ttime.tv_nsec;
    }
    u64ms = (int)round(tCurnTime.tv_nsec / 1000000);
    u64ms += tCurnTime.tv_sec * 1000;

    if(u64ms >=  u64Timeout_ms)
        return OUTTIME_DELAY_RETURN_VAL_OUTTIME;
    *pu64out_remaining_time_val = u64Timeout_ms - u64ms;
    return OUTTIME_DELAY_RETURN_VAL_WAIT_OUTTIME;
}


/**
 
	u32StartTime : 计时开始时间
	u32OutTime   ；超时时间
	u8MaxTimeoutNum  : 最大超时次数
	注意:在调用此函数时，要判断是否需要清ptOutTime->u8Count	= 0 , 如果需要需调用ClearOutTime先清状态 
*/

int set_outtime(PT_OutTime ptOutTime ,struct timespec tStartTime  , uint64_t u64OutTime , uint8_t u8MaxTimeoutNum )
{
	if(ptOutTime == NULL)
	{
		return -1;
	}
	
    /*
        超时计数部分暂时未实现
    */
	ptOutTime->u8Count	   = 0;
	
	ptOutTime->tStartTime      = tStartTime;
	ptOutTime->u64ms_Timeout   = u64OutTime;
	ptOutTime->u8MaxTimeoutNum = u8MaxTimeoutNum;
	return 0;
}

/*
    返回当前与set_time设定的间隔时间，单位：ms
*/
uint64_t get_difftime(PT_OutTime ptOutTime )
{
    struct timespec tCurnTime;
    uint64_t u64ms = 0;
    if(ptOutTime == NULL)
	{
		return 0;
	}
    clock_gettime(CLOCK_MONOTONIC,&tCurnTime);
    tCurnTime.tv_sec    -= ptOutTime->tStartTime.tv_sec;
    if(tCurnTime.tv_nsec < ptOutTime->tStartTime.tv_nsec)
    {
        tCurnTime.tv_nsec += (1000000000 - ptOutTime->tStartTime.tv_nsec);
    }
    else
    {
        tCurnTime.tv_nsec -= ptOutTime->tStartTime.tv_nsec;
    }
    u64ms = (int)round(tCurnTime.tv_nsec / 1000000);
    u64ms += tCurnTime.tv_sec * 1000;
    return u64ms;
}



void clear_outtime(PT_OutTime ptOutTime)
{
	if(ptOutTime == NULL)
	{
		return;
	}
	memset(ptOutTime , 0 ,sizeof(T_OutTime));
}


